<?php


namespace BeReborn\Cache;


use BeReborn\Base\Component;
use BeReborn\Core\JSON;
use Exception;

/**
 * Class Implode
 * @package BeReborn\Cache
 */
class Implode extends Component
{

	/** @var \Redis */
	public $redis;

	public $index = 0;

	public $savePath = '';

	/**
	 * @param string $dir
	 * @return bool|void
	 * @throws Exception
	 */
	public function implode($dir = '')
	{
		$this->savePath = $this->createSavePath($dir);
		if (!file_exists($this->savePath)) {
			return false;
		}
		return $this->resolve();
	}

	/**
	 * @param string $savePath
	 * @return string
	 * @throws Exception
	 */
	private function createSavePath($savePath = '')
	{
		if (empty($savePath)) {
			$savePath = \BeReborn::getRuntimePath();
		}

		if (!is_dir($savePath)) {
			throw new Exception('Sorry, Save path is not a directory.');
		}

		$savePath .= '/redis_export_' . $this->index . '_' . time() . '.data';
		if (!is_writable($savePath)) {
			throw new Exception('Sorry, No File Operating Permission.');
		}
		return $savePath;
	}

	/**
	 * @return bool
	 * @throws Exception
	 */
	private function resolve()
	{
		$json = file_get_contents($this->savePath);
		if (empty($json)) {
			return $this->addError('Open File error.');
		}

		$explode = explode(PHP_EOL, $json);

		$this->redis->multi(\Redis::PIPELINE);
		foreach ($explode as $key => $val) {
			$this->each(json_decode($val, true));
		}
		$this->redis->exec();
		return true;
	}

	/**
	 * @param $data
	 * @throws Exception
	 */
	private function each($data)
	{
		if (empty($data) || !is_array($data)) {
			return;
		}
		foreach ($data as $val) {
			$json = JSON::decode($val);
			if (empty($json) || !is_array($json)) {
				continue;
			}
			$this->typeImplode($json);
		}
		$this->addError('implode data num: ' . count($data));
	}

	/**
	 * @param $val
	 */
	private function typeImplode($val)
	{
		if ($val['type'] == \Redis::REDIS_SET) {
			$this->setDataBySet($val);
		} else if ($val['type'] == \Redis::REDIS_ZSET) {
			$this->setDataByZSet($val);
		} else if ($val['type'] == \Redis::REDIS_HASH) {
			$this->redis->hMSet($val['value'], $val['data']);
		} else if ($val['type'] == \Redis::REDIS_STRING) {
			$this->redis->set($val['value'], $val['data']);
		} else if ($val['type'] == \Redis::REDIS_LIST) {
			$this->setDataByLRange($val);
		} else {
			$this->redis->set($val['value'], $val['data']);
		}
	}

	/**
	 * @param $val
	 */
	private function setDataBySet($val)
	{
		if (empty($val['data']) || !is_array($val['data'])) {
			return;
		}
		foreach ($val['data'] as $value) {
			$this->redis->sAdd($val['value'], $value);
		}
	}

	/**
	 * @param $val
	 */
	private function setDataByZSet($val)
	{
		if (empty($val['data']) || !is_array($val['data'])) {
			return;
		}
		foreach ($val['data'] as $value) {
			list($score, $member) = $value;
			$this->redis->zAdd($val['value'], null, $score, $member);
		}
	}

	/**
	 * @param $val
	 */
	private function setDataByLRange($val)
	{
		if (empty($val['data']) || !is_array($val['data'])) {
			return;
		}
		foreach ($val['data'] as $datum) {
			$this->redis->lPush($val['value'], $datum);
		}
	}

}
